Ext.util.CSS = function()
{
	var rules = null;
	var doc = document;

	var camelRe = /(-[a-z])/gi;
	var camelFn = function( m, a )
	{
		return a.charAt(1).toUpperCase();
	};

	var pub =
	{
		// 添加style标签，到head标签中......
		createStyleSheet: function( cssText, id )
		{
			var ss;
			var head = doc.getElementsByTagName("head")[0];
			var rules = doc.createElement("style");
			rules.setAttribute("type", "text/css");
			if( id )
			{
				rules.setAttribute("id", id);
			}
			if( Ext.isIE ) // IE
			{
				head.appendChild(rules);
				ss = rules.styleSheet;
				ss.cssText = cssText;
			}
			else
			{
				try
				{
					rules.appendChild(doc.createTextNode(cssText));
				}
				catch (e)
				{
					rules.cssText = cssText;
				}
				head.appendChild(rules);
				ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length - 1]);
			}
			this.cacheStyleSheet(ss);
			return ss;
		},

		// 通过ID移出css文件
		removeStyleSheet: function( id )
		{
			var existing = doc.getElementById(id);
			if( existing )
			{
				existing.parentNode.removeChild(existing);
			}
		},

		// 切换css文件
		swapStyleSheet: function( id, url )
		{
			// 移除之
			this.removeStyleSheet(id);

			// 创建link标签并赋值属性
			var ss = doc.createElement("link");
			ss.setAttribute("rel", "stylesheet");
			ss.setAttribute("type", "text/css");
			ss.setAttribute("id", id);
			ss.setAttribute("href", url);

			// 添加到head元素中......
			doc.getElementsByTagName("head")[0].appendChild(ss);
		},

		/**
		 * Refresh the rule cache if you have dynamically added stylesheets
		 * 
		 * @return {Object} An object (hash) of rules indexed by selector
		 */
		refreshCache: function()
		{
			return this.getRules(true);
		},

		// 缓存样式表
		cacheStyleSheet: function( ss )
		{
			if( !rules )
			{
				rules = {};
			}
			try
			{// try catch for cross domain access issue
				var ssRules = ss.cssRules || ss.rules;
				for( var j = ssRules.length - 1; j >= 0; --j )
				{
					rules[ssRules[j].selectorText.toLowerCase()] = ssRules[j];
				}
			}
			catch (e)
			{
			}
		},

		/**
		 * Gets all css rules for the document
		 * 
		 * @param {Boolean} refreshCache true to refresh the internal cache
		 * @return {Object} An object (hash) of rules indexed by selector
		 */
		getRules: function( refreshCache )
		{
			if( rules === null || refreshCache )
			{
				rules = {};
				var ds = doc.styleSheets;
				for( var i = 0, len = ds.length; i < len; i++ )
				{
					try
					{
						this.cacheStyleSheet(ds[i]);
					}
					catch (e)
					{
					}
				}
			}
			return rules;
		},

		/**
		 * Gets an an individual CSS rule by selector(s)
		 * 
		 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
		 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
		 * @return {CSSRule} The CSS rule or null if one is not found
		 */
		getRule: function( selector, refreshCache )
		{
			var rs = this.getRules(refreshCache);
			if( !Ext.isArray(selector) )
			{
				return rs[selector.toLowerCase()];
			}
			for( var i = 0; i < selector.length; i++ )
			{
				if( rs[selector[i]] )
				{
					return rs[selector[i].toLowerCase()];
				}
			}
			return null;
		},

		/**
		 * Updates a rule property
		 * 
		 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
		 * @param {String} property The css property
		 * @param {String} value The new value for the property
		 * @return {Boolean} true If a rule was found and updated
		 */
		updateRule: function( selector, property, value )
		{
			if( !Ext.isArray(selector) )
			{
				var rule = this.getRule(selector);
				if( rule )
				{
					rule.style[property.replace(camelRe, camelFn)] = value;
					return true;
				}
			}
			else
			{
				for( var i = 0; i < selector.length; i++ )
				{
					if( this.updateRule(selector[i], property, value) )
					{
						return true;
					}
				}
			}
			return false;
		}
	};

	return pub;
}();